package com.tqfframe.task.learning.annotations;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.SmartInitializingSingleton;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.MethodIntrospector;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.Map;

/**
 * Created by Tang-QiFeng on 2020/7/18
 */
//@Component
public class JobConfig implements ApplicationContextAware, SmartInitializingSingleton {

    private static final Logger logger = LoggerFactory.getLogger(JobConfig.class);

    private static ApplicationContext applicationContext;

    @Override
    public void afterSingletonsInstantiated() {

        initJobHandlerMap(applicationContext);

    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    public void initJobHandlerMap(ApplicationContext applicationContext){
        if (applicationContext == null) {
            return;
        }
        // 获取所有bean的名称，afterSingletonsInstantiated方法表示加载完所有bean再执行这个方法。所以这样就可以获取所有bean了
        String[] beanDefinitionNames = applicationContext.getBeanNamesForType(Object.class, false, true);
        for (String beanDefinitionName : beanDefinitionNames) {
            Object bean = applicationContext.getBean(beanDefinitionName);

            Map<Method, JobHandler> annotatedMethods = null;   // referred to ：org.springframework.context.event.EventListenerMethodProcessor.processBean
            try {
                //查询出bean中带@JobHandler 注解的方法
                annotatedMethods = MethodIntrospector.selectMethods(bean.getClass(),
                        new MethodIntrospector.MetadataLookup<JobHandler>() {
                            @Override
                            public JobHandler inspect(Method method) {
                                return AnnotatedElementUtils.findMergedAnnotation(method, JobHandler.class);
                            }
                        });
            } catch (Throwable ex) {
                logger.error("error for bean[" + beanDefinitionName + "].", ex);
            }
            if (annotatedMethods==null || annotatedMethods.isEmpty()) {
                continue;
            }

            for (Map.Entry<Method, JobHandler> methodXxlJobEntry : annotatedMethods.entrySet()) {
                Method method = methodXxlJobEntry.getKey();
                JobHandler jobHandler = methodXxlJobEntry.getValue();
                if (jobHandler == null) {
                    continue;
                }
                String name = jobHandler.value();
                method.setAccessible(true);
                RegistHandlerJobMap.putJobHandlerMap(name, new JobHandlerEntry(bean,method));
            }


        }
    }

}
